﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System.Text;
using System.Runtime.Serialization;
using System;
using System.Threading;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using BrainTechLLC.ThreadSafeObjects;
using WordsMatching;
using System.Xml.Serialization;
using System.Collections.Specialized;
using System.Collections.ObjectModel;
#if USE_HYPER
using Hyper.ComponentModel;
#endif

namespace BrainTechLLC
{
#if NO_SILVERLIGHT
    [EditorBrowsable(EditorBrowsableState.Always)]
    //[TypeDescriptionProvider(typeof(HyperTypeDescriptionProvider))]
#endif
    [Serializable]
    [DataContract]
    public class BaseClass : BaseSavable, IGameThing, IFromTemplate, IHasPropertyData, ICanSaveAndRestore, IAssociatedID, IViewableThing
    {
        [DataMember]
        public NameAndDescription _name;

        [DataMember]
        public PropertyData _properties;

        [DataMember]
        public long _templateID;

        public long TemplateID { get { return _templateID; } set { _templateID = value; } }

        //[NonSerialized, XmlIgnore]
        //public ThreadSafeLookup<long, IGameThing> _dependencies;

        public virtual IViewOfThing GetViewWhenObservedBy(ICanObserveViewable looker, ViewType viewType)
        {
            return null;
        }

        public void AddOrSetProperty(string name, object o)
        {
            ThingProperties.Props.AddOrSet(name, new IdentifierAndValue() { Identifier = name, Value = o });
        }

        public int PropertiesCount { get { return _properties == null ? 0 : ThingProperties.Count; } }

#if NO_SILVERLIGHT
        [Browsable(true)]
        [TypeConverter(typeof(ExpandableObjectConverter))]
        [EditorBrowsable(EditorBrowsableState.Always)]
#endif
        [XmlIgnore]
        public PropertyData ThingProperties
        {
            get
            {
                if (_properties == null)
                    Interlocked.CompareExchange<PropertyData>(ref _properties, new PropertyData(), null);

                return _properties;
            }
            set
            {
                if (!_properties.AreEqual(value))
                {
                    OnPropertyChanging("ThingProperties", _properties, value);
                    _properties = value;
                    OnPropertyChanged("ThingProperties", _properties, value);
                }
            }
        }

#if NO_SILVERLIGHT
        [EditorBrowsable(EditorBrowsableState.Always), Browsable(true)]
#endif
        [XmlIgnore]
        [DoNotWriteBack]
        public virtual ITemplate TemplateObject
        {
            get { return null; }
            set { }
        }


#if NO_SILVERLIGHT
        [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
#endif
        [XmlIgnore]
        public NameAndDescription NameInfo
        {
            get { return Name; }
            set { Name = value; }
        }

        public virtual ObservableCollection<IdentifierAndValue> ObservableProperties
        {
            get
            {
                return ThingProperties.Props.AllItems.ToObservable();
            }
        }

        public virtual float KeywordMatchStrength(string matchString, out string bestMatch)
        {
            if (string.IsNullOrEmpty(matchString))
            {
                bestMatch = string.Empty;
                return 1.0f;
            }

            if (_name == null)
            {
                bestMatch = string.Empty;
                return 0f;
            }

            return Name.KeywordMatchStrength(matchString, out bestMatch);
        }

        public virtual bool IssueCommand(ICommandToPerform command)
        {
            return false;
        }

        public T GetProperty<T>(string name)
        {
            IdentifierAndValue o;

            if (!ThingProperties.Props.TryGetValue(name, out o))
                return default(T);

            if (o.Value == null)
                return default(T);

            return (T)Convert.ChangeType(o.Value, typeof(T), null);
        }

        [Category("Name and Description")]
        [XmlIgnore]
        [DoNotWriteBack]
        public string ShortName
        {
            get { return (_name == null) ? "(no name)" : _name.Name; }
            set
            {
                if (_name == null || !_name.Name.AreEqual(value))
                {
                    Name.Name = value;
                }
            }
        }

        [Category("Name and Description")]
        [XmlIgnore]
        [DoNotWriteBack]
        public string ShortDescription
        {
            get { return (_name == null) ? "(no short desc)" : _name.ShortDescription; }
            set
            {
                if (_name == null || !_name.ShortDescription.AreEqual(value))
                {
                    Name.ShortDescription = value;
                }
            }
        }

        [Category("Name and Description")]
        [XmlIgnore]
        [DoNotWriteBack]
        public string OneLineDescription
        {
            get { return (_name == null) ? "(no OneLine desc)" : _name.OneLineDescription; }
            set
            {
                if (_name == null || !_name.OneLineDescription.AreEqual(value))
                {
                    Name.OneLineDescription = value;
                }
            }
        }

        [Category("Name and Description")]
        [XmlIgnore]
        [DoNotWriteBack]
        public string FriendlyUniqueName
        {
            get { return (_name == null) ? "(no unique name)" : _name.FriendlyUniqueName; }
            set
            {
                if (_name == null || !_name.FriendlyUniqueName.AreEqual(value))
                {
                    Name.FriendlyUniqueName = value;
                }
            }
        }

        [Category("Name and Description")]
        [XmlIgnore]
        [DoNotWriteBack]
        public string Keywords
        {
            get { return (_name == null) ? "(no keywords)" : _name.Keywords; }
            set
            {
                if (_name == null || !_name.Keywords.AreEqual(value))
                {
                    Name.Keywords = value;
                }
            }
        }

        //[Category("Misc")]
        //[XmlIgnore]
        //public ThreadSafeLookup<long, IGameThing> Dependencies
        //{
        //    get
        //    {
        //        if (_dependencies == null)
        //            Interlocked.CompareExchange<ThreadSafeLookup<long, IGameThing>>(ref _dependencies, new ThreadSafeLookup<long, IGameThing>(), null);

        //        return _dependencies;
        //    }
        //}

        [Category("Name and Description")]
        [DisplayName("Name Info")]
        [XmlIgnore]
        public virtual NameAndDescription Name
        {
            get
            {
                if (_name == null)
                    Interlocked.CompareExchange<NameAndDescription>(ref _name, new NameAndDescription(), null);

                return _name;
            }
            set
            {
                if (!_name.AreEqual(value))
                {
                    OnPropertyChanging("Name", _name, value);
                    _name = value;
                    OnPropertyChanged("Name", _name, value);
                }
            }
        }


#if NO_SILVERLIGHT
        [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
#endif
        [XmlIgnore]
        [DoNotWriteBack]
        string INameAndDescription.Name
        {
            get { return Name.Name; }
            set { Name.Name = value; }
        }

        public virtual void RegisterChildrenForPropertyChangeEvents()
        {
            ThingProperties.PropertyChanged += new PropertyChangedEventHandler(Properties_PropertyChanged);
#if NO_SILVERLIGHT
            ThingProperties.PropertyChanging += new PropertyChangingEventHandler(Properties_PropertyChanging);
            ThingProperties.CollectionChanged += new NotifyCollectionChangedEventHandler(Properties_CollectionChanged);
#else
            ThingProperties.PropertyChanging += new EventHandler<PropertyChangingEventArgsEx>(ThingProperties_PropertyChanging);
            ThingProperties.CollectionChanged += new EventHandler<NotifyCollectionChangedEventArgsEx<IdentifierAndValue>>(ThingProperties_CollectionChanged);
#endif
            ThingProperties.RegisterForPropertyChange();
        }

        void ThingProperties_PropertyChanging(object sender, PropertyChangingEventArgsEx e)
        {

        }

        void ThingProperties_CollectionChanged(object sender, NotifyCollectionChangedEventArgsEx<IdentifierAndValue> e)
        {
            OnCollectionChanged(sender, e);
        }

#if NO_SILVERLIGHT
        void Properties_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            OnCollectionChanged(sender, e);
        }

        void Properties_PropertyChanging(object sender, PropertyChangingEventArgs e)
        {
            PropertyChangingEventArgsEx args = e as PropertyChangingEventArgsEx;
            OnPropertyChanging(sender, args);
        }
#else
        void Properties_CollectionChanged(object sender, NotifyCollectionChangedEventArgsEx<IdentifierAndValue> e)
        {
            OnCollectionChanged(sender, e);
        }

        void Properties_PropertyChanging(object sender, PropertyChangingEventArgsEx e)
        {
            PropertyChangingEventArgsEx args = e as PropertyChangingEventArgsEx;
            OnPropertyChanging(sender, args);
        }
#endif

        void Properties_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            PropertyChangedEventArgsEx args = e as PropertyChangedEventArgsEx;
            OnPropertyChanged(sender, args);
        }

        public override void PerformPostRestoreSetup()
        {
            Register();
        }
    }
}